﻿using AiQiuQuan.Sport.Core;
using AiQiuQuan.Sport.Core.WechatPayV3;
using AiQiuQuan.Sport.Model;
using AiQiuQuan.Sport.Model.Enums;
using AiQiuQuan.Sport.Model.Models;
using AiQiuQuan.Sport.WebApi.Core;
using AiQiuQuan.Sport.WebApi.Entities;
using AiQiuQuan.Sport.WebApi.Repositories;
using AiQiuQuan.Sport.WebClient;
using Microsoft.EntityFrameworkCore;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using Microsoft.Extensions.Options;
using AiQiuQuan.Sport.Core.Tool;
using DotNetCore.CAP;
using RedLockNet;

namespace AiQiuQuan.Sport.WebApi.Services.Impl
{
    /// <summary>
    /// 支付相关服务
    /// </summary>
    public partial class PayService : IPayService
    {
        private readonly ApiUrl _apiUrl;
        private readonly ICurrentInfo _currentInfo;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IBaseUserRepository _baseUserRepository;
        private readonly IVenueUserCardRepository _venueUserCardRepository;
        private readonly IVenueUserCardRecordService _venueUserCardRecordService;
        private readonly IVenueClientService _venueClientService;
        private readonly IPayOrderRepository _payOrderRepository;
        private readonly IWeChatPayOrderDetailedRepository _weChatPayOrderRepository;
        private readonly IOptions<WechatPayOption> _options;
        private readonly IVenueMemberCardRepository _venueMemberCardRepository;
        private readonly ILogger<PayService> _logger;
        private readonly ICapPublisher _capPublisher;
        private readonly IRefundOrderRepository _refundOrderRepository;
        private readonly IDistributedLockFactory _distributedLockFactory;
        private readonly IGameOrderRepository _gameOrderRepository;
        private readonly IActivityRepository _activityRepository;
        private readonly IActivityUserRepository _activityUserRepository;
        private readonly ISiteOrderRepository _siteOrderRepository;
        private readonly IVenueInfoRepository _venueInfoRepository;
        private readonly ISiteOrderDetailRepository _siteDetailRepository;
        private readonly IVenueInfoAccountRepository _venueInfoAccountRepository;
        private readonly ISitePriceListRepository _sitePriceListRepository;
        private readonly IVenueInfoRefundRuleConfigRepository _venueInfoRefundRuleConfigRepository;
        private readonly IDictionarieRepository _ictionarieRepository;
        private readonly IWechatPayV3HttpClientFactory _wechatPayV3HttpClientFactory;
        private readonly ICourseOrderRepository _courseOrderRepository;
        private readonly IGameTeamRepository _gameTeamRepository;
        private readonly IGameRepository _gameRepository;
        private readonly IBallRepository _ballRepository;
        private readonly IBallUserRepository _ballUserRepository;

        /// <summary>
        /// ctor
        /// </summary>
        public PayService(
            ApiUrl apiUrl,
            ICurrentInfo currentInfo,
            IUnitOfWorkManager unitOfWorkManager,
            IBaseUserRepository baseUserRepository,
            IVenueUserCardRepository venueUserCardRepository,
            IVenueUserCardRecordService venueUserCardRecordService,
            IVenueClientService venueClientService,
            IPayOrderRepository payOrderRepository,
            IWeChatPayOrderDetailedRepository weChatPayOrderRepository,
            IOptions<WechatPayOption> options,
            IVenueMemberCardRepository venueMemberCardRepository,
            ILogger<PayService> logger,
            ICapPublisher capPublisher,
            IGameOrderRepository gameOrderRepository,
            IActivityRepository activityRepository,
            IActivityUserRepository activityUserRepository,
            IRefundOrderRepository refundOrderRepository,
            IDistributedLockFactory distributedLockFactory,
            ISiteOrderRepository siteOrderRepository,
            IVenueInfoRepository venueInfoRepository,
            ISiteOrderDetailRepository siteDetailRepository,
            IDictionarieRepository ictionarieRepository,
            IVenueInfoAccountRepository venueInfoAccountRepository,
            ISitePriceListRepository sitePriceListRepository,
            IWechatPayV3HttpClientFactory wechatPayV3HttpClientFactory,
            IVenueInfoRefundRuleConfigRepository venueInfoRefundRuleConfigRepository,
            ICourseOrderRepository courseOrderRepository,
            IGameTeamRepository gameTeamRepository,
            IGameRepository gameRepository,
            IBallRepository ballRepository,
            IBallUserRepository ballUserRepository)
        {
            _apiUrl = apiUrl;
            _logger = logger;
            _options = options;
            _capPublisher = capPublisher;
            _currentInfo = currentInfo;
            _unitOfWorkManager = unitOfWorkManager;
            _baseUserRepository = baseUserRepository;
            _venueUserCardRepository = venueUserCardRepository;
            _venueUserCardRecordService = venueUserCardRecordService;
            _venueClientService = venueClientService;
            _payOrderRepository = payOrderRepository;
            _weChatPayOrderRepository = weChatPayOrderRepository;
            _venueMemberCardRepository = venueMemberCardRepository;
            _gameOrderRepository = gameOrderRepository;
            _activityRepository = activityRepository;
            _activityUserRepository = activityUserRepository;
            _refundOrderRepository = refundOrderRepository;
            _distributedLockFactory = distributedLockFactory;
            _venueInfoAccountRepository = venueInfoAccountRepository;
            _sitePriceListRepository = sitePriceListRepository;
            _ictionarieRepository = ictionarieRepository;
            _siteOrderRepository = siteOrderRepository;
            _venueInfoRepository = venueInfoRepository;
            _siteDetailRepository = siteDetailRepository;
            _wechatPayV3HttpClientFactory = wechatPayV3HttpClientFactory;
            _venueInfoRefundRuleConfigRepository = venueInfoRefundRuleConfigRepository;
            _courseOrderRepository = courseOrderRepository;
            _gameTeamRepository = gameTeamRepository;
            _gameRepository = gameRepository;
            _ballRepository = ballRepository;
            _ballUserRepository = ballUserRepository;
        }

        /// <summary>
        /// 获取支付信息
        /// </summary>
        /// <param name="request">PayInfoRequestDto</param>
        public async Task<PayInfoDto> GetPayInfoAsync(PayInfoRequestDto request)
        {
            var payInfo = new PayInfoDto();
            var user = await _baseUserRepository.FirstOrDefaultAsync(m => m.U_OpenId == _currentInfo.MiniProgramOpenId);
            if (user == null)
            {
                return payInfo;
            }

            payInfo.UserId = user.ID;
            payInfo.BusinessType = request.BusinessType;
            //场馆订单
            if (request.BusinessType == BusinessTypeEnum.VenueSite)
            {
                //增加场馆会员卡支付方式
                payInfo.PayTypeList.Add(new NameValue<string, int>
                {
                    Name = PayTypeEnum.VenueMemberCard.ToEnumDescription(),
                    Value = (int)PayTypeEnum.VenueMemberCard
                });

                //返回有效会员卡列表
                var queryable = from userCard in _venueUserCardRepository.AsNoTracking()
                                join card in _venueMemberCardRepository.AsNoTracking()
                                on userCard.CardId equals card.ID
                                where userCard.UserId == user.ID && userCard.ExpireTime >= DateTimeOffset.Now
                                select new VenueUserCardPayDto
                                {
                                    ID = userCard.ID,
                                    Balance = userCard.Balance,
                                    CardName = card.Name,
                                    CardType = userCard.CardType,
                                    Discount = userCard.Discount,
                                    TimesCount = userCard.TimesCount,
                                    VenueId = card.VenueId
                                };

                payInfo.VenueMemberCardList = await queryable.ToListAsync();
                if (payInfo.VenueMemberCardList.Count > 0)
                {
                    var siteOrder = await _siteOrderRepository.FirstOrDefaultAsync(m => m.ID == request.OrderId);
                    if (siteOrder != null)
                    {
                        var venue = await _venueInfoRepository.FirstOrDefaultAsync(m => m.ID == siteOrder.VenueInfoID);
                        var siteOrderDetailCount = await _siteDetailRepository.CountAsync(m => m.SiteOrderID == siteOrder.ID);
                        //设置订单信息的次数
                        payInfo.OrderInfo.TimesCount = venue.VenueHourType == VenueHourTypeEnum.OneHour ? siteOrderDetailCount : (siteOrderDetailCount * 1.0M / 2);

                        payInfo.VenueMemberCardList = payInfo.VenueMemberCardList
                            .Where(m => m.VenueId == siteOrder.VenueInfoID).ToList();
                        foreach (var item in payInfo.VenueMemberCardList)
                        {
                            var discountAmount = Math.Round(siteOrder.SO_ActualPrice * (item.Discount / 10), 2);
                            if ((item.CardType == MemberCardTypeEnum.Times && item.TimesCount >= payInfo.OrderInfo.TimesCount)
                            || (item.CardType == MemberCardTypeEnum.Discount && item.Balance >= discountAmount)
                            || item.Balance >= siteOrder.SO_ActualPrice)
                            {
                                item.IsEnable = true;
                            }

                            item.VenueName = venue.VI_Name;
                        }
                    }
                }
            }

            //订单信息数据查询
            await SetOrderInfoAsync(payInfo, request);

            return payInfo;
        }

        /// <summary>
        /// 支付
        /// </summary>
        public async Task<UnaryResult<PayResultDto>> PayAsync(PayRequestDto request)
        {
            UnaryResult<PayResultDto> result = null;
            var payResult = new PayResultDto { BusinessType = request.BusinessType, OrderId = request.OrderId, PayType = request.PayType };
            var payInner = new PayOrderInnerInfo { ClientType = request.ClientType };
            BaseUser user = null;
            var stateList = new List<PayOrderStateEnum> { PayOrderStateEnum.Paid, PayOrderStateEnum.PartialRefunded, PayOrderStateEnum.Refunded };
            var faildStateList = new List<PayOrderStateEnum> { PayOrderStateEnum.NotPay, PayOrderStateEnum.Canceled, PayOrderStateEnum.Expired };
            if (await _payOrderRepository.AnyAsync(m => m.BusinessId == request.OrderId && m.BusinessType == request.BusinessType && stateList.Contains(m.PayState)))
            {
                return UnaryResult.From(10, payResult, "订单已支付");
            }

            await _payOrderRepository.DeleteAsync(m => m.BusinessId == request.OrderId && faildStateList.Contains(m.PayState) && m.BusinessType == request.BusinessType);

            switch (request.ClientType)
            {
                case ClientTypeEnum.MiniProgram:
                    user = await _baseUserRepository.FirstOrDefaultAsync(m => m.U_OpenId == _currentInfo.MiniProgramOpenId);
                    break;
                case ClientTypeEnum.APP:
                    break;
            }

            if (user == null)
            {
                return UnaryResult.From(10, payResult, $"未查询到当前用户信息：{_currentInfo.MiniProgramOpenId}");
            }

            payInner.UserId = user.ID;

            await using (var redlock = await _distributedLockFactory.CreateLockAsync(request.OrderId.ToString("N"), TimeSpan.FromSeconds(20)))
            {
                if (!redlock.IsAcquired)
                {
                    return UnaryResult.From(10, payResult, $"请匆重复支付，稍后重试");
                }

                //分业务类型进行逻辑判断，赋值内部订单数据
                switch (request.BusinessType)
                {
                    case BusinessTypeEnum.VenueSite:
                        result = await PayVenueOrderAsync(request, payInner, payResult, user);
                        break;
                    case BusinessTypeEnum.Ball:
                    case BusinessTypeEnum.Activity:
                    case BusinessTypeEnum.Game:
                        result = await PayGameOrderAsync(request, payInner, payResult, user);
                        break;
                    case BusinessTypeEnum.Course:
                        result = await PayCourseOrderAsync(request, payInner, payResult, user);
                        break;
                }

                if (result.Code != 0)
                {
                    return result;
                }

                //分支付方式，执行支付/预支付
                switch (request.PayType)
                {
                    case PayTypeEnum.WXPay:
                        result = await WxPayAsync(payInner, request, payResult);
                        break;
                    case PayTypeEnum.AliPay:
                        return UnaryResult.From(10, payResult, "暂不支持支付宝支付方式");
                    case PayTypeEnum.VenueMemberCard:
                        result = await VenueCardPayAsync(payInner, request, payResult, user);
                        break;
                }

                if (result.Code != 0)
                {
                    return result;
                }

                //保存统一支付单,场馆会员卡支付内部已保存支付单(为保证数据库事务统一性)
                if (request.PayType != PayTypeEnum.VenueMemberCard)
                {
                    await AddPayOrderAsync(request, payInner);
                }

                return result;
            }
        }

        /// <summary>
        /// 退款
        /// </summary>
        public async Task<UnaryResult<RefundResultDto>> RefundAsync(RefundRequestDto request)
        {
            await using (var redlock = await _distributedLockFactory.CreateLockAsync(request.OrderId.ToString("N"), TimeSpan.FromSeconds(20)))
            {
                if (!redlock.IsAcquired)
                {
                    return UnaryResult.From<RefundResultDto>(10, null, $"请匆重复退款，稍后重试");
                }

                var payOrder = await _payOrderRepository.FirstOrDefaultAsync(m => m.BusinessId == request.OrderId);
                if (payOrder != null)
                {
                    if (payOrder.PayState == PayOrderStateEnum.Refunded || payOrder.PayState == PayOrderStateEnum.Canceled || payOrder.PayState == PayOrderStateEnum.Expired)
                    {
                        return UnaryResult.From<RefundResultDto>(10, null, $"支付订单状态不正确");
                    }

                    if (await _refundOrderRepository.AnyAsync(m => m.PayOrderId == payOrder.ID && m.State == RefundStateEnum.Processing))
                    {
                        return UnaryResult.From<RefundResultDto>(10, null, $"订单退款进行中");
                    }
                }

                var result = new RefundResultDto { BusinessType = request.BusinessType, OrderNo = payOrder?.OrderNo, RefundRemark = request.Remark, ExtJson = request.AttachData };
                //分业务执行退款逻辑
                var unaryResult = await ExecuteRefundOrderAsync(request, payOrder, result);
                return unaryResult;
            }
        }

        #region private methods

        /// <summary>
        /// 订单信息数据查询
        /// </summary>
        private async Task SetOrderInfoAsync(PayInfoDto payInfo, PayInfoRequestDto request)
        {
            switch (request.BusinessType)
            {
                case BusinessTypeEnum.VenueSite:
                    var siteOrder = await _siteOrderRepository.FirstOrDefaultAsync(m => m.ID == request.OrderId);
                    if (siteOrder != null)
                    {
                        payInfo.OrderInfo.OrderId = siteOrder.ID;
                        payInfo.OrderInfo.OrderAmount = siteOrder.SO_TotalPrice;
                        payInfo.OrderInfo.PayAmount = siteOrder.SO_ActualPrice;
                        payInfo.OrderInfo.ProductDescription = siteOrder.SO_OrderRemark;
                        payInfo.OrderInfo.ProductName = "场馆场地消费";
                    }

                    break;
                case BusinessTypeEnum.Activity:
                case BusinessTypeEnum.Ball:
                case BusinessTypeEnum.Game:
                    var gameOrder = await _gameOrderRepository.FirstOrDefaultAsync(m => m.ID == request.OrderId);
                    if (gameOrder != null)
                    {
                        payInfo.OrderInfo.OrderId = gameOrder.ID;
                        payInfo.OrderInfo.OrderAmount = gameOrder.OrderAmount;
                        payInfo.OrderInfo.PayAmount = gameOrder.PayAmount;
                        payInfo.OrderInfo.ProductDescription = gameOrder.Remark;
                        payInfo.OrderInfo.ProductName = gameOrder.Name;
                    }

                    break;
                case BusinessTypeEnum.Course:
                    var courseOrder = await _courseOrderRepository.FirstOrDefaultAsync(m => m.ID == request.OrderId);
                    if (courseOrder != null)
                    {
                        payInfo.OrderInfo.OrderId = courseOrder.ID;
                        payInfo.OrderInfo.OrderAmount = courseOrder.OrderAmount;
                        payInfo.OrderInfo.PayAmount = courseOrder.PayAmount;
                        payInfo.OrderInfo.ProductDescription = courseOrder.Remark;
                        payInfo.OrderInfo.ProductName = courseOrder.Name;
                    }

                    break;
                default:
                    break;
            }
        }

        #region 支付相关逻辑
        /// <summary>
        /// 支付订单
        /// </summary>
        /// <param name="request">PayRequestDto</param>
        /// <param name="payOrderInner">订单必要信息</param>
        private async Task AddPayOrderAsync(PayRequestDto request, PayOrderInnerInfo payOrderInner)
        {
            var payOrder = await _payOrderRepository.FirstOrDefaultAsync(m => m.BusinessId == request.OrderId);
            if (payOrder == null)
            {
                payOrder = new PayOrder
                {
                    BusinessId = request.OrderId,
                    BusinessType = request.BusinessType,
                    OrderNo = payOrderInner.OrderNo,
                    ProductName = payOrderInner.ProductName,
                    ProductDescription = payOrderInner.ProductDescription,
                    PayType = request.PayType,
                    PayState = payOrderInner.PayState,
                    PrePayId = payOrderInner.PrePayId,
                    PayId = string.Empty,
                    Payer = payOrderInner.Payer,
                    PayRemark = payOrderInner.PayRemark,
                    OrderAmount = payOrderInner.OrderAmount,
                    PayAmount = payOrderInner.PayAmount,
                    DiscountAmount = payOrderInner.DiscountAmount,
                    CompensationAmount = request.CompensationAmount,
                    CashAmount = request.CashAmount,
                    RefundAmount = 0,
                    RefundRemark = string.Empty,
                    ExtJson = payOrderInner.ExtJson,
                    UserId = payOrderInner.UserId,
                    PayTime = payOrderInner.PayTime,
                    ClientType = payOrderInner.ClientType,
                };
                await _payOrderRepository.AddAsync(payOrder);

                if (payOrderInner.IsCompatibleVenueOrder && request.PayType == PayTypeEnum.WXPay && request.BusinessType == BusinessTypeEnum.VenueSite)
                {
                    var oldPayOrder = new WeChatPayOrderDetailed
                    {
                        WPOD_OrderNo = payOrderInner.OrderNo,
                        WPOD_WeChatOrderNo = string.Empty,
                        WPOD_PayMoeny = request.PayAmount * 100,
                        WPOD_PayRemark = payOrderInner.PayRemark,
                        WPOD_State = payOrderInner.PayState,
                        WPOD_PaySource = request.BusinessType,
                        WPOD_RefundMoney = 0,
                        BaseUserId = payOrderInner.UserId
                    };
                    await _weChatPayOrderRepository.AddAsync(oldPayOrder);
                }
            }
        }

        /// <summary>
        /// 微信支付
        /// </summary>
        private async Task<UnaryResult<PayResultDto>> WxPayAsync(PayOrderInnerInfo payInner, PayRequestDto request, PayResultDto result)
        {
            payInner.NotifyUrl = $"{_apiUrl.BaseUrl}v2/payorder/wxpay_callback";
            var wxPayClient = _wechatPayV3HttpClientFactory.Create();
            var payOrder = await _payOrderRepository.FirstOrDefaultAsync(m => m.BusinessId == request.OrderId);
            if (payOrder == null)
            {
                if (request.ClientType == ClientTypeEnum.MiniProgram)
                {
                    var wxRequest = new CreatePayTransactionJsapiRequest
                    {
                        AppId = _options.Value.AppId,
                        MerchantId = _options.Value.MchId,
                        Description = payInner.ProductDescription,
                        OutTradeNumber = payInner.OrderNo,
                        NotifyUrl = payInner.NotifyUrl,
                        Amount = new CreatePayTransactionJsapiRequest.Types.Amount { Total = (int)(request.PayAmount * 100) },
                        Payer = new CreatePayTransactionJsapiRequest.Types.Payer { OpenId = payInner.Payer },
                        Attachment = JsonTool.JsonSerialize(new PayAttachDto { PaySource = request.BusinessType, BusinessType = request.BusinessType })
                    };
                    var rep = await wxPayClient.ExecuteCreatePayTransactionJsapiAsync(wxRequest);
                    if (!rep.IsSuccessful())
                    {
                        return UnaryResult.From(10, result, $"{rep.ErrorCode}_{rep.ErrorMessage}");
                    }

                    result.PrePayId = rep.PrepayId;
                    payInner.PrePayId = rep.PrepayId;
                }
                else if (request.ClientType != ClientTypeEnum.APP)
                {
                    var wxRequest = new CreatePayTransactionAppRequest
                    {
                        AppId = _options.Value.AppId,
                        MerchantId = _options.Value.MchId,
                        Description = payInner.ProductDescription,
                        OutTradeNumber = payInner.OrderNo,
                        NotifyUrl = payInner.NotifyUrl,
                        Amount = new CreatePayTransactionAppRequest.Types.Amount { Total = (int)(request.PayAmount * 100) },
                        Attachment = JsonTool.JsonSerialize(JsonTool.JsonSerialize(new PayAttachDto { PaySource = request.BusinessType, BusinessType = request.BusinessType }))
                    };
                    var rep = await wxPayClient.ExecuteCreatePayTransactionAppAsync(wxRequest);
                    if (!rep.IsSuccessful())
                    {
                        return UnaryResult.From(10, result, $"{rep.ErrorCode}_{rep.ErrorMessage}");
                    }

                    result.PrePayId = rep.PrepayId;
                    payInner.PrePayId = rep.PrepayId;
                }
            }
            else
            {
                result.PrePayId = payOrder.PrePayId;
            }

            switch (request.ClientType)
            {
                case ClientTypeEnum.H5:
                    break;
                case ClientTypeEnum.MiniProgram:
                    result.PayData = wxPayClient.GenerateParametersForJsapiPayRequest(_options.Value.AppId, result.PrePayId);
                    break;
                case ClientTypeEnum.APP:
                    result.PayData = wxPayClient.GenerateParametersForAppPayRequest(_options.Value.AppId, result.PrePayId);
                    break;
            }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 场馆会员卡支付
        /// </summary>
        private async Task<UnaryResult<PayResultDto>> VenueCardPayAsync(PayOrderInnerInfo payInner, PayRequestDto request, PayResultDto result, BaseUser user)
        {
            var userCard = await _venueUserCardRepository.FirstOrDefaultAsync(m => m.UserId == payInner.UserId && m.ID == request.VenueUserCardId && m.ExpireTime >= DateTimeOffset.Now);
            if (userCard == null)
            {
                return UnaryResult.From(10, result, $"未查询到用户场馆会员卡信息：{request.VenueUserCardId}");
            }

            var siteOrder = await _siteOrderRepository.FirstOrDefaultAsync(m => m.ID == request.OrderId && m.SO_State == VenueOrderStateEnum.NoPay);
            //验证会员卡余额及次数,次卡数据更改
            payInner.PayState = PayOrderStateEnum.Paid;
            var extJson = new PayVenueCardExtJsonDto
            {
                CardId = request.VenueUserCardId,
                CardType = userCard.CardType,
                Discount = userCard.Discount,
            };
            //分场馆会员卡类型判断及赋值
            switch (userCard.CardType)
            {
                case MemberCardTypeEnum.Discount:
                case MemberCardTypeEnum.Storage:
                    var discountAmount = Math.Round(siteOrder.SO_ActualPrice * (userCard.Discount / 10), 2);
                    if (userCard.CardType == MemberCardTypeEnum.Discount && discountAmount != request.PayAmount)
                    {
                        return UnaryResult.From<PayResultDto>(10, null, $"场馆会员折扣卡折扣金额错误：{discountAmount}");
                    }

                    if (userCard.CardType == MemberCardTypeEnum.Discount)
                    {
                        payInner.PayAmount = discountAmount;
                    }

                    if (userCard.Balance < payInner.PayAmount)
                    {
                        return UnaryResult.From<PayResultDto>(10, null, $"会员卡余额不足：{userCard.Balance}");
                    }

                    break;
                case MemberCardTypeEnum.Times:
                    var venue = await _venueInfoRepository.FirstOrDefaultAsync(m => m.ID == siteOrder.VenueInfoID);
                    var venueOrderDeatailCount = await _siteDetailRepository.CountAsync(m => m.SiteOrderID == siteOrder.ID);
                    var timesCount = venue.VenueHourType == VenueHourTypeEnum.OneHour ? venueOrderDeatailCount : venueOrderDeatailCount * 1.0M / 2;
                    if (userCard.TimesCount < timesCount)
                    {
                        return UnaryResult.From<PayResultDto>(10, null, $"会员卡次数不足：{userCard.TimesCount}");
                    }

                    payInner.OrderAmount = timesCount;
                    payInner.DiscountAmount = 0;
                    payInner.PayAmount = timesCount;
                    extJson.TimesCount = timesCount;

                    break;
            }

            payInner.ExtJson = JsonTool.JsonSerialize(extJson);

            //扣减场馆会员卡金额及相关表数据
            await UpdateVenueOrderAsync(siteOrder, userCard, user, request, payInner);
            try
            {
                //调用接口，发送公众号消息
                await _venueClientService.VenueMemberCardPaySuccessAsync(_apiUrl.BaseUrl, request.OrderId);
            }
            catch { }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 场馆会员卡支付订单成功数据更新
        /// </summary>
        private async Task UpdateVenueOrderAsync(SiteOrder siteOrder, VenueUserCard userCard, BaseUser user, PayRequestDto request, PayOrderInnerInfo payInner)
        {
            //场馆订单
            siteOrder.SO_State = VenueOrderStateEnum.NoUse;
            siteOrder.SO_ActualPrice = userCard.CardType == MemberCardTypeEnum.Times ? siteOrder.SO_ActualPrice : payInner.PayAmount;
            siteOrder.SO_DiscountPrice = siteOrder.SO_TotalPrice - siteOrder.SO_ActualPrice;
            siteOrder.CardAmount = payInner.PayAmount;
            siteOrder.PayType = request.PayType;
            siteOrder.UserVenueCardId = request.VenueUserCardId;
            siteOrder.CardDiscount = userCard.Discount;
            siteOrder.MemberCardType = userCard.CardType;

            //场馆会员卡余额
            if (userCard.CardType == MemberCardTypeEnum.Times)
            {
                userCard.TimesCount -= payInner.PayAmount;
            }
            else
            {
                userCard.Balance -= payInner.PayAmount;
            }

            //场馆会员卡账户记录
            var record = new VenueUserCardRecordAddDto
            {
                VenueId = userCard.VenueId,
                UserCardId = userCard.ID,
                CardType = userCard.CardType,
                UserId = userCard.UserId,
                UserCode = user.U_Code,
                Type = CardRecordTypeEnum.VenueConsume,
                Balance = userCard.CardType == MemberCardTypeEnum.Times ? userCard.TimesCount : userCard.Balance,
                Amount = -payInner.PayAmount,
                Reamrk = $"用户会员卡场馆消费"
            };

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _siteOrderRepository.UpdateAsync(siteOrder);
                await _venueUserCardRepository.UpdateAsync(userCard);
                await _venueUserCardRecordService.AddAsync(record);
                await AddPayOrderAsync(request, payInner);

                await uow.CompleteAsync();
            }
        }

        #endregion

        #region 退款相关逻辑
        /// <summary>
        /// 分业务验证退款逻辑
        /// </summary>
        private async Task<UnaryResult<RefundResultDto>> ExecuteRefundOrderAsync(RefundRequestDto request, PayOrder payOrder, RefundResultDto result)
        {
            UnaryResult<RefundResultDto> unaryResult = null;
            //处理业务订单相关数据,回写结果相关result金额及其他数据
            switch (request.BusinessType)
            {
                case BusinessTypeEnum.VenueSite:
                    unaryResult = await ExecuteVenueOrderRefundAsync(request, payOrder, result);
                    break;
                case BusinessTypeEnum.Activity:
                case BusinessTypeEnum.Game:
                case BusinessTypeEnum.Ball:
                    unaryResult = await ExecuteGameOrderRefundAsync(request, payOrder, result);
                    break;
                case BusinessTypeEnum.Course:
                    unaryResult = await ExecuteCourseOrderRefundAsync(request, payOrder, result);
                    break;
            }

            //前面业务逻辑判断，必须判断未付款直接更新相关业务逻辑情况，此处好过滤
            //未付款，未生成相关支付订单
            if (unaryResult.Code != 0 || result.IsSuccess || result.RefundAmount <= 0)
            {
                return unaryResult;
            }

            //先写入进行中退款单,结果赋值退款单号
            var refundOrder = await AddRefundOrderAsync(payOrder, result);
            //执行退款
            unaryResult = await ReallyRefundAsync(request, payOrder, refundOrder, result);
            //无论成功与否，发送订阅消息
            await _capPublisher.PublishAsync(MessageTopic.ALL_REFUND_CALLBACK, result);

            return unaryResult;
        }

        /// <summary>
        /// 增加进行中退款单,结果赋值退款单号
        /// </summary>
        private async Task<RefundOrder> AddRefundOrderAsync(PayOrder payOrder, RefundResultDto result)
        {
            var refundOrder = new RefundOrder
            {
                PayOrderId = payOrder.ID,
                OrderNo = payOrder.OrderNo,
                RefundNo = Tool.BuildPayOrderNo(result.BusinessType),
                ApplyAmount = result.ApplyAmount,
                BusinessType = result.BusinessType,
                RefundAmount = result.RefundAmount,
                ServiceChargeAmount = result.ServiceChargeAmount,
                RefundId = "",
                State = RefundStateEnum.Processing,
                RefundType = payOrder.PayType,
                Remark = result.RefundRemark,
                ExtJson = string.IsNullOrWhiteSpace(result.ExtJson) ? payOrder.ExtJson : result.ExtJson,
            };
            await _refundOrderRepository.AddAsync(refundOrder);
            result.RefundNo = refundOrder.RefundNo;

            return refundOrder;
        }

        /// <summary>
        /// 执行退款
        /// </summary>
        private async Task<UnaryResult<RefundResultDto>> ReallyRefundAsync(RefundRequestDto request, PayOrder payOrder, RefundOrder refundOrder, RefundResultDto result)
        {
            switch (payOrder.PayType)
            {
                case PayTypeEnum.WXPay:
                    {
                        var wxPayClient = _wechatPayV3HttpClientFactory.Create();
                        var wxRefund = new CreateRefundDomesticRefundRequest
                        {
                            OutTradeNumber = payOrder.OrderNo,
                            OutRefundNumber = refundOrder.RefundNo,
                            Amount = new CreateRefundDomesticRefundRequest.Types.Amount
                            {
                                Total = (int)(payOrder.PayAmount * 100),
                                Refund = (int)(result.RefundAmount * 100)
                            },
                            NotifyUrl = _apiUrl.BaseUrl
                        };
                        var wxRep = await wxPayClient.ExecuteCreateRefundDomesticRefundAsync(wxRefund);
                        if (!wxRep.IsSuccessful())
                        {
                            result.IsSuccess = false;
                            result.Msg = $"{result.Msg}：{wxRep.ErrorCode}_{wxRep.ErrorMessage}";
                            _logger.LogError($"{result.Msg}：{wxRep.ErrorCode}_{wxRep.ErrorMessage}");
                            return UnaryResult.From(10, result, result.Msg);
                        }
                        else
                        {
                            result.RefundId = wxRep.RefundId;
                            result.IsSuccess = wxRep.Status == "SUCCESS" || wxRep.Status == "PROCESSING";
                            result.Msg = "微信退款成功";
                        }
                    }

                    break;
                case PayTypeEnum.AliPay:
                    break;
                case PayTypeEnum.VenueMemberCard:
                    {
                        //场馆会员卡消费退款，不记入场馆账户（场馆会员卡是线下收钱）
                        var siteOrder = await _siteOrderRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.OrderId);
                        var venueUserCard = await _venueUserCardRepository.FirstOrDefaultAsync(m => m.ID == siteOrder.UserVenueCardId);
                        if (venueUserCard == null)
                        {
                            result.IsSuccess = false;
                            result.Msg = $"未查询到场馆会员卡{siteOrder.UserVenueCardId}";
                            return UnaryResult.From(10, result, result.Msg);
                        }

                        //场馆会员卡余额
                        if (venueUserCard.CardType == MemberCardTypeEnum.Times)
                        {
                            venueUserCard.TimesCount += result.RefundAmount;
                        }
                        else
                        {
                            venueUserCard.Balance += result.RefundAmount;
                        }

                        //场馆会员卡账户记录
                        var user = await _baseUserRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == siteOrder.BaseUserID);
                        var record = new VenueUserCardRecordAddDto
                        {
                            VenueId = venueUserCard.VenueId,
                            UserCardId = venueUserCard.ID,
                            CardType = venueUserCard.CardType,
                            UserId = venueUserCard.UserId,
                            UserCode = user.U_Code,
                            Type = CardRecordTypeEnum.VenueRefund,
                            Balance = venueUserCard.CardType == MemberCardTypeEnum.Times ? venueUserCard.TimesCount : venueUserCard.Balance,
                            Amount = result.RefundAmount,
                            Reamrk = $"用户会员卡场馆消费退款"
                        };

                        using (var uow = _unitOfWorkManager.Begin())
                        {
                            await _venueUserCardRepository.UpdateAsync(venueUserCard);
                            await _venueUserCardRecordService.AddAsync(record);
                            await uow.CompleteAsync();
                        }

                        result.IsSuccess = true;
                    }

                    break;
            }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 获取额外数据中的活动报名人ID
        /// </summary>
        private List<Guid> GetRefundUserIdList(string attachData)
        {
            var result = new List<Guid>();
            if (string.IsNullOrEmpty(attachData))
            {
                return result;
            }

            foreach (var item in attachData.Trim(',').Split(','))
            {
                try
                {
                    result.Add(Guid.Parse(item));
                }
                catch
                {
                    throw new BusinessException("参赛人ID不正确");
                }
            }

            return result;
        }

        #endregion

        #endregion
    }
}